#include "stdafx.h"
#include "XHotKeySrvImpl.h"

#include "XAppData.h"
#include "Util.h"


//////////////////////////////////////////////////////////////////////////


IXHotKeyHandler::IXHotKeyHandler()
{
    ;
}

IXHotKeyHandler::~IXHotKeyHandler()
{
    if(Util::GetSkinCoreStatus() == Util::CoreStatus_Ready)
    {
        XPtr<IXHotKeySrv> pHotKeySrv = NULL;
        if(SUCCEEDED(Util::CreateObject(&pHotKeySrv)))
        {
            pHotKeySrv->DelHotKeyHandler(this);
        }
    }
}


//////////////////////////////////////////////////////////////////////////

IMPLEMENT_SKIN_CLASS(CXHotKeySrvImpl);

CXHotKeySrvImpl::CXHotKeySrvImpl()
{
    m_hHotKeySrvWnd = NULL;
}

CXHotKeySrvImpl::~CXHotKeySrvImpl()
{
}

//////////////////////////////////////////////////////////////////////////
UINT_PTR CXHotKeySrvImpl::AddHotKeyHandler(UINT uModifiers, UINT uVk, IXHotKeyHandler* pListener)
{
    HWND hWnd = GetHotKeyWnd();
    if(hWnd == NULL)
        return INVALID_HOTKEY_ID;

    XString strAtomName = XString(_T("hotatom%1")).arg(::GetTickCount());
    ATOM atomHotKey = ::GlobalAddAtom(strAtomName.c_str());
    BOOL bResult = ::RegisterHotKey(hWnd, atomHotKey, uModifiers, uVk);
    ::GlobalDeleteAtom(atomHotKey);
    if(bResult)
    {
        m_HotKeyHandlerCont[atomHotKey] = pListener;
        return atomHotKey;
    }
    else
    {
        return 0;
    }
}

void CXHotKeySrvImpl::DelHotKeyHandler(UINT_PTR uHotKeyId)
{
    HotKeyHandlerContainer::iterator Ite = m_HotKeyHandlerCont.find(uHotKeyId);
    if(Ite != m_HotKeyHandlerCont.end())
    {
        const UINT& uAtom = Ite->first;
        IXHotKeyHandler* pHandler = Ite->second;
        ::GlobalDeleteAtom((ATOM)uAtom);
        ::UnregisterHotKey(m_hHotKeySrvWnd, uHotKeyId);
        m_HotKeyHandlerCont.erase(Ite);
    }
}

void CXHotKeySrvImpl::DelHotKeyHandler(IXHotKeyHandler* pHandler)
{
    HotKeyHandlerContainer::iterator Ite = m_HotKeyHandlerCont.begin();
    while(Ite != m_HotKeyHandlerCont.end())
    {
        const UINT& uAtom = Ite->first;
        IXHotKeyHandler* p = Ite->second;
        if(p == pHandler)
        {
            ::GlobalDeleteAtom((ATOM)uAtom);
            ::UnregisterHotKey(m_hHotKeySrvWnd, uAtom);
            Ite = m_HotKeyHandlerCont.erase(Ite);
        }
        else
        {
            ++ Ite;
        }
    }
}

BOOL CXHotKeySrvImpl::IsHotKeyValid(UINT uModifiers, UINT uVk)
{
    HWND hWnd = GetHotKeyWnd();
    XString strAtomName = XString(_T("hotatom%1")).arg(::GetTickCount());
    ATOM atomHotKey = ::GlobalAddAtom(strAtomName.c_str());
    BOOL bResult = ::RegisterHotKey(hWnd, atomHotKey, uModifiers, uVk);
    ::GlobalDeleteAtom((ATOM)atomHotKey);
    if(bResult)
    {
        ::UnregisterHotKey(m_hHotKeySrvWnd, atomHotKey);
    }

    return bResult;
}

// IXBaseObj
void CXHotKeySrvImpl::OnFinalRelease()
{
    superclass::OnFinalRelease();

    if(m_hHotKeySrvWnd != NULL && ::IsWindow(m_hHotKeySrvWnd))
    {
        HotKeyHandlerContainer::iterator Ite = m_HotKeyHandlerCont.begin();
        for(; Ite != m_HotKeyHandlerCont.end(); ++ Ite)
        {
            const UINT& uAtom = Ite->first;
            IXHotKeyHandler* pHandler = Ite->second;
            ::GlobalDeleteAtom((ATOM)uAtom);
            ::UnregisterHotKey(m_hHotKeySrvWnd, uAtom);
        }
        m_HotKeyHandlerCont.clear();

        SetWindowLongPtr(m_hHotKeySrvWnd, GWLP_USERDATA, (LONG)NULL);
        ::DestroyWindow(m_hHotKeySrvWnd);
        m_hHotKeySrvWnd = NULL;
    }
    else
    {
        m_HotKeyHandlerCont.clear();
    }
}

LRESULT CXHotKeySrvImpl::HotKeyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if(message == WM_HOTKEY)
    {
        CXHotKeySrvImpl* pHotKeySrv = (CXHotKeySrvImpl*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
        if(pHotKeySrv!= NULL && pHotKeySrv->HandleHotKeyMsg(wParam))
            return 0;
    }
    else if(message == WM_DESTROY)
    {
        CXHotKeySrvImpl* pHotKeySrv = (CXHotKeySrvImpl*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
        if(pHotKeySrv != NULL)
        {
            pHotKeySrv->m_hHotKeySrvWnd = NULL;
            SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)NULL);
        }
    }

    return ::DefWindowProc(hWnd, message, wParam, lParam);
}

BOOL CXHotKeySrvImpl::HandleHotKeyMsg(UINT_PTR uHotKeyId)
{
    HotKeyHandlerContainer::iterator Ite = m_HotKeyHandlerCont.find(uHotKeyId);
    if(Ite != m_HotKeyHandlerCont.end())
    {
        IXHotKeyHandler* pHandler = Ite->second;
        if(pHandler != NULL)
        {
            return pHandler->OnHotKey(uHotKeyId);
        }
    }
    return FALSE;
}

HWND CXHotKeySrvImpl::GetHotKeyWnd()
{
    XASSERT_ERROR(m_hHotKeySrvWnd == NULL || IsWindow(m_hHotKeySrvWnd), _T("HotKeyWnd isn't valid."));
    if(m_hHotKeySrvWnd != NULL)
        return m_hHotKeySrvWnd;

#define HOT_KEY_WND_CLASS   _T("XHotKeyWnd")

    HMODULE hModule = XAppData::GetXSkinModule();
    WNDCLASSEX WndClassEx = {0};
    WndClassEx.cbSize = sizeof(WndClassEx);
    WndClassEx.hInstance = hModule;
    WndClassEx.lpfnWndProc = &CXHotKeySrvImpl::HotKeyWndProc;
    WndClassEx.lpszClassName = HOT_KEY_WND_CLASS;
    WndClassEx.style = 0;
    ATOM aTom = ::RegisterClassEx(&WndClassEx);
    if(aTom != NULL)
    {
        m_hHotKeySrvWnd = CreateWindow(HOT_KEY_WND_CLASS, _T(""),
            0,
            0, 0, 0, 0,
            HWND_MESSAGE,
            NULL,
            hModule,
            NULL);
    }

    XASSERT_ERROR(m_hHotKeySrvWnd != NULL, _T("Failed to Create HotKeyWindow"));
    if(m_hHotKeySrvWnd != NULL)
    {
        SetWindowLongPtr(m_hHotKeySrvWnd, GWLP_USERDATA, (LONG)this);
    }

    return m_hHotKeySrvWnd;
}
